/*************************************郑州精铖电力设备有限公司*****************************************************
** 通讯实验室-LoRa模块
** 研发部编写，工程专用
** 版权所有，盗版必究
************************************************文件描述***********************************************************
** 文件名：LoRa_App.c
** 描  述：LoRa API函数源文件
**
************************************************历史版本***********************************************************
** 作者：
** 日期：
** 版本：
**
************************************************使用版本***********************************************************
** 作者：李康
** 日期：20191203
** 版本：V1.0
**
**************************************************说明*************************************************************
**LoRa模块复位引脚定义		----->   LoRa_RST
**LoRa模块中断引脚DIO0定义	----->   LoRa_DIO0
**LoRa模块片选引脚定义		----->   LoRa_CS
**LoRa模块片SPI总线句柄定义 ----->   hspi1
************************************http://www.jingchengdianli.com*************************************************/

/*************************************************库头文件*********************************************************/
#include <LoRa_App.h>
#include <LoRa_Dri.h>
#include <LoRa_Reg.h>
#include "string.h"
#include "stdio.h"
/***********************************************底层驱动库头文件***************************************************/
/**************************************************全局变量********************************************************/

//内部函数，不对外调用
/***************************************************************************
* 函 数 名:  SX1276_RST
* 函数功能:  SX1276模块复位
* 输    入:  无
*
* 输    出:  无
*
* 返    回:  无
*
* 备    注:  无
* 作    者:  李康
* 日	期:  2019-12-03
****************************************************************************/
static void SX1276_RST(void);

/***************************************************************************
* 函 数 名:  LoRaSetOpMode
* 函数功能:  LoRa模块设置模式
* 输    入:  opMode 设置的模式
*
* 输    出:  无
*
* 返    回:  无
*
* 备    注:  无
* 作    者:  李康
* 日	期:  2019-12-03
****************************************************************************/
static void LoRaSetOpMode(uint8_t   opMode);

 /***************************************************************************
 * 函 数 名:  SX1276CheckSPI
 * 函数功能:  检查SPI总线通讯
 * 输    入:  无
 *
 * 输    出:  无
 *
 * 返    回:  CHECK_OK 总线通讯成功
 *				CHECK_ERR 总线通讯失败，硬件故障
 * 备    注:  无
 * 作    者:  李康
 * 日	 期:  2019-12-03
 ****************************************************************************/
static uint8_t SX1276CheckSPI(void);

 /***************************************************************************
 * 函 数 名:  SX1276SetLoRaOn
 * 函数功能:  SX1276模块设置为LoRa调制模式
 * 输    入:  无
 *
 * 输    出:  无
 *
 * 返    回:  无
 *
 * 备    注:  无
 * 作    者:  李康
 * 日	 期:  2019-12-03
 ****************************************************************************/
static void SX1276SetLoRaOn(void);

 /***************************************************************************
 * 函 数 名:  SX1276LoRaInit
 * 函数功能:  SX1276模块LoRa物理层配置
 * 输    入:  无
 *
 * 输    出:  无
 *
 * 返    回:  无
 *
 * 备    注:  无
 * 作    者:  李康
 * 日	 期:  2019-12-03
 ****************************************************************************/
static void  SX1276LoRaInit( void );

tLoRaSettings LoRaSettings =
{
    433000000,			// 发射频率 RFFrequency
    20,					// 发射功率 Power
    7,					// 信号带宽	SignalBw [0: 7.8kHz, 1: 10.4 kHz, 2: 15.6 kHz, 3: 20.8 kHz, 4: 31.2 kHz,5: 41.6 kHz, 6: 62.5 kHz,
						//	7: 125 kHz, 8: 250 kHz, 9: 500 kHz, other: Reserved]
    7,					// 扩频因数 [6: 64, 7: 128, 8: 256, 9: 512, 10: 1024, 11: 2048, 12: 4096  chips]
    1,					// 纠错编码率	ErrorCoding [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
    true,				// CRC校验	CrcOn [0: OFF, 1: ON]  CRC
    false,				// 报头模式	ImplicitHeaderOn [0: OFF, 1: ON]
    0,					// 接收模式	RxSingleOn [0: Continuous(持续接收), 1 Single(单一接收)]
    0,					// FreqHopOn [0: OFF, 1: ON]
    4,					// HopPeriod Hops every frequency hopping period symbols
    128,				// 负载长度	PayloadLength (used for implicit header mode)
};
//定义结构体指针，指向LoRa寄存器组
tSX1276LR *SX1276LR;
uint8_t SX1276Regs[0x70];

/***************************************************************************
* 函 数 名:  LoRa_Init
* 函数功能:  LoRa模块初始化配置
* 输    入:  无
*
* 输    出:  无
*
* 返    回:  无
*
* 备    注:  无
* 作    者:  李康
* 日	期:  2019-12-03
****************************************************************************/
uint8_t LoRa_Init(void)
{
	uint8_t i = 0;
    while(SX1276CheckSPI()==CHECK_ERR)
	{
		HAL_Delay(10);
		i++;
		if (i>100)
		{
			return LoRa_ERR;
		}
	}
	SX1276LR = (tSX1276LR*)SX1276Regs;						//初始化LoRa寄存器结构体
	SX1276_RST();											//重启SX1276模块
    SX1276SetLoRaOn();										//设置1276模块的工作模式(LoRa、端口映射、读取寄存器值并保存)
    SX1276LoRaInit();										//初始化LoRa调制解调器
	return LoRa_OK;
}

/***************************************************************************
* 函 数 名:  SX1276_RST
* 函数功能:  SX1276模块复位
* 输    入:  无
*
* 输    出:  无
*
* 返    回:  无
*
* 备    注:  无
* 作    者:  李康
* 日	期:  2019-12-03
****************************************************************************/
static void SX1276_RST(void)
{
	RST_L();		//将复位引脚置低
	HAL_Delay(10);
	RST_H();			//将复位引脚置高
	HAL_Delay(20);
}

/***************************************************************************
* 函 数 名:  SX1276CheckSPI
* 函数功能:  检查SPI总线通讯
* 输    入:  无
*
* 输    出:  无
*
* 返    回:  CHECK_OK 总线通讯成功
*				CHECK_ERR 总线通讯失败，硬件故障
* 备    注:  无
* 作    者:  李康
* 日	期:  2019-12-03
****************************************************************************/
static uint8_t SX1276CheckSPI(void)
{
	uint8_t Readbuffer[2] = {0x6c,0x80};						//保存复位值

	SX1276_RST();										//重启ZM470SX模块
	SX1276WriteBuffer(LoRa_FrfMsb_Reg, Readbuffer, 2);	//写入缺省值到0x06、0x07寄存器中
	Readbuffer[0] = Readbuffer[1] =0;					//清零
	SX1276ReadBuffer(LoRa_FrfMsb_Reg, Readbuffer,2);	//读取写入寄存器的值
	if(Readbuffer[0] == 0x6C)							//判断数据是否正确
		if(Readbuffer[1] == 0x80)
			return CHECK_OK;							//成功返回0
	return CHECK_ERR;									//失败返回1
}

/***************************************************************************
* 函 数 名:  SX1276SetLoRaOn
* 函数功能:  SX1276模块设置为LoRa调制模式
* 输    入:  无
*
* 输    出:  无
*
* 返    回:  无
*
* 备    注:  无
* 作    者:  李康
* 日	期:  2019-12-03
****************************************************************************/
static void SX1276SetLoRaOn(void)
{
	//设置为LORA调制
	LoRaSetOpMode( LoRa_SleepMode );			//设置为睡眠模式
														//设置为LoRa模式
	SX1276LR->OpModeReg = ( SX1276LR->OpModeReg & LoRa_OpMode_LongRangMode_Mask ) | LoRa_OpMode_LongRangMode_ON;
	SX1276Write( LoRa_OpMode_Reg, SX1276LR->OpModeReg );	//写入设定值

	//I/O口映射
	LoRaSetOpMode( LoRa_StandByMode );			//设置为待机模式
	SX1276LR->DioMapping1Reg = LoRa_DioMapping1_DIO0_00 | LoRa_DioMapping1_DIO1_00 | LoRa_DioMapping1_DIO2_00 | LoRa_DioMapping1_DIO3_00;
	SX1276LR->DioMapping2Reg = LoRa_DioMapping2_DIO4_00 | LoRa_DioMapping2_DIO5_00;
	SX1276WriteBuffer( LoRa_DioMapping1_Reg, &SX1276LR->DioMapping1Reg, 2 );

	//读取1276寄存器的值，保存在SX1276Regs中(除了FIFO读/写寄存器)
	SX1276ReadBuffer( LoRa_OpMode_Reg, SX1276Regs+1, 0x70-1 );
}

/***************************************************************************
* 函 数 名:  SX1276LoRaInit
* 函数功能:  SX1276模块LoRa物理层配置
* 输    入:  无
*
* 输    出:  无
*
* 返    回:  无
*
* 备    注:  无
* 作    者:  李康
* 日	期:  2019-12-03
****************************************************************************/
static void SX1276LoRaInit( void )
{
    SX1276ReadBuffer( LoRa_OpMode_Reg, SX1276Regs+1, 0x70-1 );		//读取寄存器的值
    SX1276LR->LnaReg = LoRa_Lna_Gain_G1;							//LAN设置为最大增益
    SX1276WriteBuffer( LoRa_OpMode_Reg, SX1276Regs+1, 0x70-1 );		//写入数组值到寄存器中

    //set the RF settings
    LoRaSetRFFrequency( LoRaSettings.RFFrequency );			//设置载波频率为433 000 000
    LoRaSetSpreadingFactor( LoRaSettings.SpreadingFactor ); 	//设置扩频因数为7
    LoRaSetErrorCoding( LoRaSettings.ErrorCoding );			//设置纠错编码率 001->4/5
    LoRaSetPacketCrcOn( LoRaSettings.CrcOn );					//开启CRC 1->CRC开启
    LoRaSetSignalBandwidth( LoRaSettings.SignalBw );			//设置带宽为500kHz 1001->500kHz

    LoRaSetImplicitHeaderOn( LoRaSettings.ImplicitHeaderOn );	//设置为显示报头模式 0->显示报头模式
    LoRaSetSymbTimeout( 0x3FF );								//设置RX超时最高有效位和最低有效位 (0x3ff)
    LoRaSetPayloadLength( LoRaSettings.PayloadLength );		//设置负载字节长度为128
    LoRaSetLowDatarateOptimize( true );						//开启低数据率优化
    LoRaSetPreambleLength(8);
    if( LoRaSettings.RFFrequency > 860000000 )
    {
        LoRaSetPAOutput( LoRa_PaConfig_PaSelect_Rfo );
        LoRaSetPa20dBm( false );
        LoRaSettings.Power = 14;
        LoRaSetRFPower( LoRaSettings.Power );
    }
    else
    {
        SX1276Write( LoRa_Ocp_Reg, 0x3f );							//默认参数PA最在电流为100mA,当输出20dBm时需要120mA
		LoRaSetPAOutput( LoRa_PaConfig_PaSelect_Paboost );	//选择PA输出引脚(PA_BOOST引脚) 输出功率<=+20dBm
        LoRaSetPa20dBm( true );								//设置最大输出功率为20dBm(最大)
        LoRaSettings.Power = 20;									//设置输出功率为20dBm
        LoRaSetRFPower( LoRaSettings.Power );					//写入输出功率值
    }
    LoRaSetOpMode( LoRa_StandByMode );						//设置为待机模式

    LoRaRxStateEnter();
}

/***************************************************************************
* 函 数 名:  LoRaSetOpMode
* 函数功能:  LoRa模式配置
* 输    入:  opMode 要配置的模式
*
* 输    出:  无
*
* 返    回:  无
*
* 备    注:  无
* 作    者:  李康
* 日	期:  2019-12-03
****************************************************************************/
void LoRaSetOpMode(uint8_t opMode)
{
    static uint8_t  opModePrev 			= LoRa_StandByMode;
    static bool antennaSwitchTxOnPrev 	= true;
    bool 		antennaSwitchTxOn 		= false;
    opModePrev = SX1276LR->OpModeReg & ~LoRa_OpMode_Mask;

    if( opMode != opModePrev )
    {
        if( opMode == LoRa_TxMode )
        {
            antennaSwitchTxOn = true;
        }
        else
        {
            antennaSwitchTxOn = false;
        }
        if( antennaSwitchTxOn != antennaSwitchTxOnPrev )
        {
            antennaSwitchTxOnPrev = antennaSwitchTxOn;
        }
        SX1276LR->OpModeReg = ( SX1276LR->OpModeReg & LoRa_OpMode_Mask ) | opMode;

        SX1276Write( LoRa_OpMode_Reg, SX1276LR->OpModeReg );
    }
}

/***************************************************************************
* 函 数 名:  LoRaRxStateEnter
* 函数功能:  LoRa模块进入接收状态
* 输    入:  无
*
* 输    出:  无
*
* 返    回:  无
*
* 备    注:  无
* 作    者:  李康
* 日	期:  2019-12-03
****************************************************************************/
void LoRaRxStateEnter(void)
{
	//1.---->进入待机模式
	LoRaSetOpMode( LoRa_StandByMode );		//操作寄存器只能在在Standby,sleep or FSTX 模式

	//2.---->接收初始化，参数设置
	SX1276LR->IrqFlagsMaskReg=~LoRa_RxDone_IRQMask ;      //打开数据包接收完成中断
	SX1276Write(LoRa_IrqFlagsMask_Reg, SX1276LR->IrqFlagsMaskReg);		//设置需要屏蔽的中断,写0打开

    SX1276LR->HopPeriodReg = 255;
	SX1276Write(LoRa_HopPeriod_Reg, SX1276LR->HopPeriodReg);			//频率跳变之间的符号周期:255

    //DIO0:RxDone
	//DIO0~DIO3引脚映射
    SX1276LR->DioMapping1Reg = 	LoRa_DioMapping1_DIO0_00|LoRa_DioMapping1_DIO1_11 |LoRa_DioMapping1_DIO2_11 |LoRa_DioMapping1_DIO3_11;
	//DIO4~DIO5引脚映射
	SX1276LR->DioMapping2Reg = 	LoRa_DioMapping2_DIO4_10|LoRa_DioMapping2_DIO5_11;


    SX1276WriteBuffer( LoRa_DioMapping1_Reg, &SX1276LR->DioMapping1Reg, 2 );	//配置5个IO的功能
//	SX1276Write( LoRa_IrqFlags_Reg,0xff);	//清除所有中断标志

	//3.---->设置接收模式(单次/持续模式)
	if( LoRaSettings.RxSingleOn == true )		//设置为单次接收
	{
		LoRaSetOpMode( LoRa_RXSINGLEMode );
	}
	else		//设置为持续接收模式
	{
		SX1276LR->FifoRxBaseAddrReg=0x00;
		SX1276LR->FifoAddrPtrReg = SX1276LR->FifoRxBaseAddrReg;		  	//内容:0x00
		SX1276Write( LoRa_FifoAddrPtr_Reg, SX1276LR->FifoAddrPtrReg );	//SPI访问FIFO的地址
		SX1276Write( LoRa_FifoAddrPtr_Reg,0x00);
		LoRaSetOpMode( LoRa_RXCONTINUOUSMode);           			//进入接收状态
	}

}
/***************************************************************************
* 函 数 名:  LoRaReadbuffer
* 函数功能: 读取 LoRa模块接收到的数据
* 输    入:  pbuf  接收数据存放的地址 
*				size接收数据长度存放的地址
* 输    出:  无
*
* 返    回:  LoRa_OK 接收完成
*				LoRa_ERR 接收失败
* 备    注:  无
* 作    者:  李康
* 日	期:  2019-12-03
****************************************************************************/
uint8_t LoRaReadBuffer(uint8_t *pbuf, uint8_t *size)
{
	uint8_t temp;
	//4.---->等待数据接收完成
	SX1276Read(LoRa_IrqFlags_Reg,&temp);
	if (temp&0X40)
	{
		SX1276Read(LoRa_IrqFlags_Reg, &SX1276LR->IrqFlagsReg);
		if (SX1276LR->IrqFlagsReg & LoRa_RxDone_IrqFlags)
		{                                                  				//RxDone
			SX1276Write(LoRa_IrqFlags_Reg, LoRa_RxDone_IrqFlags);		//执行写操作以清除接收中断标志
			SX1276Read(LoRa_IrqFlags_Reg, &SX1276LR->IrqFlagsReg);			//读取中断状态标志位
			//5.---->检测CRC标志，以验证数据包的完整性
			if ((SX1276LR->IrqFlagsReg & LoRa_PayloadCrcError_IrqFlags) == LoRa_PayloadCrcError_IrqFlags)
			{
				SX1276Write(LoRa_IrqFlags_Reg, LoRa_PayloadCrcError_IrqFlags);	//执行写操作以清除接收中断标志
				return LoRa_ERR;
			}
			//6.---->读取接收到的数据
			SX1276Read(LoRa_FifoRxCurrentAddr_Reg, &SX1276LR->FifoRxCurrentAddrReg);	//读取最后接收一包数据首指针

			//隐式报头模式
			if (LoRaSettings.ImplicitHeaderOn == true)
			{
				SX1276Read(LoRa_RxNbBytes_Reg, size);
				SX1276LR->FifoAddrPtrReg = SX1276LR->FifoRxCurrentAddrReg;
				SX1276Write(LoRa_FifoAddrPtr_Reg, SX1276LR->FifoAddrPtrReg);			//写入FIFO的访问地址
				SX1276ReadFifo(pbuf, *size);
			}
			//显式报头模式
			else
			{
				SX1276Read(LoRa_RxNbBytes_Reg, size);	 						//读取数据包包长度(size记录数据包的长度)
				SX1276LR->FifoAddrPtrReg = SX1276LR->FifoRxCurrentAddrReg;		//将最后接收的数据包的首地址赋予FIFO数据缓冲区的访问地址(SPI)
				SX1276Write(LoRa_FifoAddrPtr_Reg, SX1276LR->FifoAddrPtrReg);  	//写入FIFO的访问地址
				SX1276ReadFifo(pbuf, *size);									//读取FIFO中的数据，并保存在pbuf中
			}
			LoRaRxStateEnter();
			return LoRa_OK;
		}
		else
		{
			return LoRa_ERR;
		}
		
	}
	else
	{
		return LoRa_ERR;
	}

}

/***************************************************************************
* 函 数 名:  LoRaTxData
* 函数功能:  LoRa模块发送数据
* 输    入:  pbuf  发送数据存放的地址   
*				size 数据长度
* 输    出:  无
*
* 返    回:  LoRa_OK 发送成功
*				LoRa_ERR 发送失败
* 备    注:  无
* 作    者:  李康
* 日	期:  2019-12-03
****************************************************************************/
uint8_t LoRaSendBuffer (uint8_t *pbuf, uint8_t size)
{
	uint8_t temp,i,errcode=LoRa_OK;
	if ( pbuf==0 || size==0 )	//没有数据可发送
	{
		errcode=LoRa_ERR;				//发送失败 -- 返回1
	}
	//1.------>进入待机状态
    LoRaSetOpMode( LoRa_StandByMode );

	//2.------>发送初始化  //打开发送完成中断
	SX1276LR->IrqFlagsMaskReg = ~LoRa_TxDone_IRQMask;
	SX1276Write( LoRa_IrqFlagsMask_Reg, SX1276LR->IrqFlagsMaskReg );
	SX1276LR->HopPeriodReg = 0;											//频率跳变之间的符号时周期为：0
	SX1276Write( LoRa_HopPeriod_Reg, SX1276LR->HopPeriodReg);

	//初始化待发送数据所占缓存区的大小
	SX1276LR->PayloadLengthReg = size; 									//数据负载长度(不包括CRC长度)
	SX1276Write( LoRa_PayloadLength_Reg, SX1276LR->PayloadLengthReg); 	//在implicit模式(隐式包头),必须写入FIFO长度

	SX1276LR->FifoTxBaseAddrReg = 0x00;                                 //发送基地址设置为0x00
	SX1276Write( LoRa_FifoTxBaseAddr_Reg, SX1276LR->FifoTxBaseAddrReg);  //写入发送的首地址

	SX1276LR->FifoAddrPtrReg = SX1276LR->FifoTxBaseAddrReg;				//FIFO地址指针指向Tx基地址
	SX1276Write( LoRa_FifoAddrPtr_Reg, SX1276LR->FifoAddrPtrReg );        //写入FIFO的访问地址

	//3.------>将待发送的数据写入到FIFO中
	SX1276WriteFifo( pbuf, SX1276LR->PayloadLengthReg );	            //写入要发送的数据

	//DIO0:TxDone  端口映射设置
	SX1276LR->DioMapping1Reg = LoRa_DioMapping1_DIO0_01 | LoRa_DioMapping1_DIO1_11| LoRa_DioMapping1_DIO2_11 | LoRa_DioMapping1_DIO3_11;
	SX1276LR->DioMapping2Reg = LoRa_DioMapping2_DIO4_00 | LoRa_DioMapping2_DIO5_11;
	SX1276WriteBuffer(LoRa_DioMapping1_Reg,&SX1276LR->DioMapping1Reg,2);
	///////////////////////////////////////////////////////////////////////////////

	//4.------>进入到发送模式，发送数据
    LoRaSetOpMode(LoRa_TxMode);		//进入发送状态
	while(temp!=0x08)
	{
		HAL_Delay(1);
		i++;
		if(i>300)
		{
			errcode=LoRa_ERR;
			break;
		}
		SX1276Read(LoRa_IrqFlags_Reg,&temp);	//如果发送失败
	}
	SX1276Write( LoRa_IrqFlags_Reg,LoRa_TxDone_IrqFlags);	//清除发送完成中断
	LoRaRxStateEnter();
	return errcode;												//成功 -- 返回0
}
